#region COPYRIGHT
//--------------------------------------------------------------------------------
// <copyright file="Billow.cs" company="starLiGHT Entertainment Studios">
//    Copyright (c) 2007, 2008, 2009, 2010, 2011
//       Roland Rosenkranz (Glatzemann@email.de)
//
//    Based on libnoise by Jason Bevins
//      Copyright (C) 2003, 2004 Jason Bevins (licensed under LGPL)
// </copyright>
// <license>
//   This file is part of starLiGHT.Noise.
//
//   starLiGHT.Noise is free software: you can redistribute it and/or modify
//   it under the terms of the GNU Lesser General Public License as published by
//   the Free Software Foundation, either version 3 of the License, or
//   (at your option) any later version.
//
//   starLiGHT.Noise is distributed in the hope that it will be useful,
//   but WITHOUT ANY WARRANTY; without even the implied warranty of
//   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//   GNU Lesser General Public License for more details.
//
//   You should have received a copy of the GNU Lesser General Public License
//   along with starLiGHT.Noise. If not, see http://www.gnu.org/licenses/.
//    
//   ADDITIONAL (commercial) LICENSES for starLiGHT.Noise are available on request.
// </license>
// <version>
// **************[ starLiGHT.Engine SVN ]**********************
// * $Rev:: 10385                 $:  Revision of last commit *
// * $Author:: unknown            $:  Author of last commit   *
// * $Date:: 2011-06-14 07:59:17 #$:  Date of last commit     *
// ************************************************************
// </version>
//--------------------------------------------------------------------------------
#endregion

namespace starLiGHT.Noise.Noise
{
    #region Using Statements
    using System;
    using System.Collections.Generic;
    using System.Text;

    #endregion

    /// This noise module generates "billowy" noise suitable for clouds and
    /// rocks.
    ///
    /// This noise module is nearly identical to noise::module::Perlin except
    /// this noise module modifies each octave with an absolute-value
    /// function.  See the documentation of noise::module::Perlin for more
    /// information.
    public class Billow : Module
    {
        /// Frequency of the first octave.
        protected double frequency;

        /// Frequency multiplier between successive octaves.
        protected double lacunarity;

        /// Quality of the billowy noise.
        protected NoiseQuality noiseQuality;

        /// Total number of octaves that generate the billowy noise.
        protected int octaveCount;

        /// Persistence value of the billowy noise.
        protected double persistence;

        /// Seed value used by the billowy-noise function.
        protected int seed;

        /// Default frequency for the noise::module::Billow noise module.
        private const double DEFAULT_BILLOW_FREQUENCY = 1.0;

        /// Default lacunarity for the the noise::module::Billow noise module.
        private const double DEFAULT_BILLOW_LACUNARITY = 2.0;

        /// Default number of octaves for the the noise::module::Billow noise
        /// module.
        private const int DEFAULT_BILLOW_OCTAVE_COUNT = 6;

        /// Default persistence value for the the noise::module::Billow noise
        /// module.
        private const double DEFAULT_BILLOW_PERSISTENCE = 0.5;

        /// Default noise quality for the the noise::module::Billow noise module.
        private const NoiseQuality DEFAULT_BILLOW_QUALITY = NoiseQuality.QUALITY_STD;

        /// Default noise seed for the the noise::module::Billow noise module.
        private const int DEFAULT_BILLOW_SEED = 0;

        /// Maximum number of octaves for the the noise::module::Billow noise
        /// module.
        private const int BILLOW_MAX_OCTAVE = 30;

        private List<Parameter> parameterList;

        public Billow() : base(0)
        {
            this.frequency = DEFAULT_BILLOW_FREQUENCY;
            this.lacunarity = DEFAULT_BILLOW_LACUNARITY;
            this.noiseQuality = DEFAULT_BILLOW_QUALITY;
            this.octaveCount = DEFAULT_BILLOW_OCTAVE_COUNT;
            this.persistence = DEFAULT_BILLOW_PERSISTENCE;
            this.seed = DEFAULT_BILLOW_SEED;
        }

        public override List<Parameter> ParameterList
        {
            get
            {
                if (this.parameterList == null)
                {
                    this.parameterList = new List<Parameter>();
                    this.parameterList.Add(new Parameter("Seed", "int", DEFAULT_BILLOW_SEED, int.MinValue, int.MaxValue));
                    this.parameterList.Add(new Parameter("Persistence", "double", DEFAULT_BILLOW_PERSISTENCE, 0.0, 1.0));
                    this.parameterList.Add(new Parameter("OctaveCount", "int", DEFAULT_BILLOW_OCTAVE_COUNT, 1, BILLOW_MAX_OCTAVE));
                    this.parameterList.Add(new Parameter("NoiseQuality", "enum", NoiseQuality.QUALITY_STD, null, null));
                    this.parameterList.Add(new Parameter("Frequency", "double", DEFAULT_BILLOW_FREQUENCY, 0.0, 16.0));
                    this.parameterList.Add(new Parameter("Lacunarity", "double", DEFAULT_BILLOW_LACUNARITY, 0.0, 5.0));
                }

                return this.parameterList;
            }
        }

        /// Returns the frequency of the first octave.
        public double GetFrequency()
        {
          return this.frequency;
        }

        /// Returns the lacunarity of the billowy noise.
        /// 
        /// The lacunarity is the frequency multiplier between successive
        /// octaves.
        public double GetLacunarity()
        {
          return this.lacunarity;
        }

        /// Returns the quality of the billowy noise.
        ///
        /// See noise::NoiseQuality for definitions of the various
        /// coherent-noise qualities.
        public NoiseQuality GetNoiseQuality()
        {
          return this.noiseQuality;
        }

        /// Returns the number of octaves that generate the billowy noise.
        ///
        /// The number of octaves controls the amount of detail in the billowy
        /// noise.
        public int GetOctaveCount()
        {
          return this.octaveCount;
        }

        /// Returns the persistence value of the billowy noise.
        ///
        /// The persistence value controls the roughness of the billowy noise.
        public double GetPersistence()
        {
          return this.persistence;
        }

        /// Returns the seed value used by the billowy-noise function.
        public int GetSeed()
        {
          return this.seed;
        }

        public override double GetValue(double x, double y, double z, double lowerXBound, double upperXBound, double lowerZBound, double upperZBound)
        {
            double value = 0.0;
            double signal = 0.0;
            double curPersistence = 1.0;
            double nx, ny, nz;
            int seed;

            x *= this.frequency;
            y *= this.frequency;
            z *= this.frequency;

            for (int curOctave = 0; curOctave < this.octaveCount; curOctave++)
            {
                // Make sure that these floating-point values have the same range as a 32-
                // bit integer so that we can pass them to the coherent-noise functions.
                nx = noisegen.MakeInt32Range(x);
                ny = noisegen.MakeInt32Range(y);
                nz = noisegen.MakeInt32Range(z);

                // Get the coherent-noise value from the input value and add it to the
                // final result.
                seed = (int)((this.seed + curOctave) & 0xffffffff);
                signal = noisegen.GradientCoherentNoise3D(nx, ny, nz, seed, this.noiseQuality);
                signal = (2.0 * Math.Abs(signal)) - 1.0;
                value = value + (signal * curPersistence);

                // Prepare the next octave.
                x *= this.lacunarity;
                y *= this.lacunarity;
                z *= this.lacunarity;
                curPersistence *= this.persistence;
            }

            value += 0.5;

            return value;
        }

        /// Sets the frequency of the first octave.
        public void SetFrequency(double frequency)
        {
          this.frequency = frequency;
        }

        /// Sets the lacunarity of the billowy noise.
        ///
        /// The lacunarity is the frequency multiplier between successive octaves.
        /// For best results, set the lacunarity to a number between 1.5 and 3.5.
        public void SetLacunarity(double lacunarity)
        {
          this.lacunarity = lacunarity;
        }

        /// Sets the quality of the billowy noise.
        ///
        /// See noise::NoiseQuality for definitions of the various coherent-noise qualities.
        public void SetNoiseQuality(NoiseQuality noiseQuality)
        {
          this.noiseQuality = noiseQuality;
        }

        /// Sets the number of octaves that generate the billowy noise.
        ///
        /// @pre The number of octaves ranges from 1 to noise::module::BILLOW_MAX_OCTAVE.
        ///
        /// @throw noise::ExceptionInvalidParam An invalid parameter was specified; see the preconditions for more information.
        ///
        /// The number of octaves controls the amount of detail in the billowy noise.
        ///
        /// The larger the number of octaves, the more time required to calculate the billowy-noise value.
        public void SetOctaveCount(int octaveCount)
        {
          if (octaveCount < 1 || octaveCount > BILLOW_MAX_OCTAVE) {
            throw new Exception("invalid params");
          }
          this.octaveCount = octaveCount;
        }

        /// Sets the persistence value of the billowy noise.
        ///
        /// The persistence value controls the roughness of the billowy noise.
        ///
        /// For best results, set the persistence value to a number between 0.0 and 1.0.
        public void SetPersistence(double persistence)
        {
          this.persistence = persistence;
        }

        /// Sets the seed value used by the billowy-noise function.
        public void SetSeed(int seed)
        {
          this.seed = seed;
        }

        public override void SetParameter(string name, object value)
        {
            switch (name.ToLower())
            {
                case "seed":
                    this.SetSeed(Convert.ToInt32(value));
                    break;
                case "persistence":
                    this.SetPersistence(Convert.ToDouble(value));
                    break;
                case "octavecount":
                    this.SetOctaveCount(Convert.ToInt32(value));
                    break;
                case "noisequality":
                    this.SetNoiseQuality((NoiseQuality)value);
                    break;
                case "frequency":
                    this.SetFrequency(Convert.ToDouble(value));
                    break;
                case "lacunarity":
                    this.SetLacunarity(Convert.ToDouble(value));
                    break;
            }
        }

        public override object GetParameter(string name)
        {
            switch (name.ToLower())
            {
                case "seed": return this.GetSeed();
                case "persistence": return this.GetPersistence();
                case "octavecount": return this.GetOctaveCount();
                case "noisequality": return this.GetNoiseQuality();
                case "frequency": return this.GetFrequency();
                case "lacunarity": return this.GetLacunarity();
            }

            return null;
        }
    }
}
